/*
 *  $Id$
 *  Copyright [2010] [Panxiaobo] 
 *  Licensed under the Apache License, Version 2.0 (the "License"); 
 *  you may not use this file except in compliance with the License. 
 *  You may obtain a copy of the License at
 *  
 *     http://www.apache.org/licenses/LICENSE-2.0
 *     
 *  Unless required by applicable law or agreed to in writing, software 
 *  distributed under the License is distributed on an "AS IS" BASIS, 
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
 *  See the License for the specific language governing permissions and 
 *  limitations under the License. 
 */
package pxb.openid.ns;

import java.util.Collections;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

/**
 * openid attribute exchange 1.0的实现,
 * <p>
 * 1.在RP端发送请求时使用
 * 
 * <pre>
 * Map<String,String> mapSendToOP = new Ax().askForFirstName(true).askForLastName(false).request().toMap();
 * 以上代码等价于
 * Map<String,String> mapSendToOP = new Ax().askFor("http://axschema.org/namePerson/first",true).askFor("http://axschema.org/namePerson/first",false).request().toMap();
 * </pre>
 * 
 * </p>
 * <p>
 * 2.在OP端收到RP请求时使用
 * 
 * <pre>
 * if(Ax.hasAx(mapFromRP)){
 *  Ax ax=new Ax(mapFromRP)
 *  if(ax.isAskForFirstName()){
 *   ax.xFirstName("super man");
 *  }
 *  Map<String,String> mapToRP=ax.response().toMap();
 * }
 * 以上代码等价于
 * if(Ax.hasAx(mapFromRP)){
 *  Ax ax=new Ax(mapFromRP)
 *  if(ax.isAskFor("http://axschema.org/namePerson/first")){
 *   ax.setAxValue("http://axschema.org/namePerson/first","super man");
 *  }
 *  Map<String,String> mapToRP=ax.response().toMap();
 * }
 * </pre>
 * 
 * </p>
 * <p>
 * 3.在RP端收到OP的数据时
 * 
 * <pre>
 * if(Ax.hasAx(mapFromOp)){
 *  Ax ax=new Ax(mapFromOP);
 *  System.out.println(ax.getFirstName());
 * }
 * 以上代码等价于
 * if(Ax.hasAx(mapFromOp)){
 *  Ax ax=new Ax(mapFromOP);
 *  System.out.println(ax.getAxValue("http://axschema.org/namePerson/first"));
 * }
 * 
 * </pre>
 * 
 * </p>
 * 
 * @author Panxiaobo
 * 
 */
public class Ax extends Base {

    public static final String COUNTRY = "country";

    public static final String EMAIL = "email";

    public static final String FIRSTNAME = "firstname";

    public static final String LANGUAGE = "language";
    public static final String LASTNAME = "lastname";
    public static final String NS = "http://openid.net/srv/ax/1.0";
    public static final String NS_COUNTRY = "http://axschema.org/contact/country/home";
    public static final String NS_EMAIL = "http://axschema.org/contact/email";

    public static final String NS_FIRSTNAME = "http://axschema.org/namePerson/first";
    public static final String NS_LANGUAGE = "http://axschema.org/pref/language";
    public static final String NS_LASTNAME = "http://axschema.org/namePerson/last";

    /**
     * 是否存在ax命名空间
     * 
     * @param map
     * @return
     */
    public static boolean hasAx(Map<String, String> map) {
        return null != getNs(map, NS);
    }

    private Set<String> requestRequired = new HashSet<String>();

    public Ax() {
        super(NS, "ax");
    }

    public Ax(Map<String, String> map) {
        super(map, NS);
    }

    public Ax askFor(String ns, boolean required) {
        return askFor(null, ns, required);
    }

    public Ax askFor(String name, String ns, boolean required) {
        if (name == null) {
            name = "x" + (ns.hashCode() & 0x0FFFF);
        }
        if (required) {
            requestRequired.add(name);
        }
        put("type." + name, ns);
        return this;
    }

    public Ax askForCountry(boolean required) {
        return askFor(COUNTRY, NS_COUNTRY, required);
    }

    public Ax askForEmail(boolean required) {
        return askFor(EMAIL, NS_EMAIL, required);

    }

    public Ax askForFirstName(boolean required) {
        return askFor(FIRSTNAME, NS_FIRSTNAME, required);

    }

    public Ax askForLanguage(boolean required) {
        return askFor(LANGUAGE, NS_LANGUAGE, required);
    }

    public Ax askForLastName(boolean required) {
        return askFor(LASTNAME, NS_LASTNAME, required);

    }

    /**
     * 返回RP向OP请求的数据的命名空间
     * 
     * @return a set of Name Space
     */
    public Set<String> getAsked() {
        Set<String> set = new HashSet<String>();
        String p = prefix + "type.";
        for (Map.Entry<String, String> entry : map.entrySet()) {
            if (entry.getKey().startsWith(p)) {
                set.add(entry.getValue());
            }
        }
        return Collections.unmodifiableSet(set);
    }

    public String getAxName(String ns) {
        String p = prefix + "type.";
        for (Map.Entry<String, String> entry : map.entrySet()) {
            if (entry.getValue().equals(ns) && entry.getKey().startsWith(p)) {
                String name = entry.getKey();
                return name.substring(p.length());
            }
        }
        return null;
    }

    public String getAxValue(String ns) {
        String name = getAxName(ns);
        if (name == null)
            return null;
        return get("value." + name);
    }

    public String getCountry() {
        return getAxValue(NS_COUNTRY);
    }

    public String getEmail() {
        return getAxValue(NS_EMAIL);
    }

    public String getFirstName() {
        return getAxValue(NS_FIRSTNAME);
    }

    public String getLanguage() {
        return getAxValue(NS_LANGUAGE);
    }

    public String getLastName() {
        return getAxValue(NS_LASTNAME);
    }

    @Override
    public Map<String, String> getMap() {
        if ("fetch_request".equals(get("mode"))) {
            StringBuilder sb = new StringBuilder();
            for (String s : requestRequired) {
                sb.append(',').append(s);
            }
            if (sb.length() > 0)
                sb.deleteCharAt(0);
            put("required", sb.toString());
        } else {
            remove("required");
        }
        return super.getMap();
    }

    /**
     * 返回RP向OP请求必须数据的命名空间
     * 
     * @return a set of Name Space
     */
    public Set<String> getRequired() {
        String requiredString = get("required");
        String[] requiredShortName = requiredString.split(",");
        Set<String> set = new HashSet<String>();
        for (String aa : requiredShortName) {
            set.add(get("type." + aa));
        }
        return Collections.unmodifiableSet(set);
    }

    public boolean isAskFor(String ns) {
        return null != getAxName(ns);
    }

    public boolean isAskForCountry() {
        return isAskFor(COUNTRY);
    }

    public boolean isAskForEmail() {
        return isAskFor(EMAIL);
    }

    public boolean isAskForFirstName() {
        return isAskFor(FIRSTNAME);
    }

    public boolean isAskForLanguage() {
        return isAskFor(LANGUAGE);
    }

    public boolean isAskForLastName() {
        return isAskFor(LASTNAME);
    }

    /**
     * 标记为RP 向 OP 的请求
     * 
     * @return
     */
    public Ax request() {
        put("mode", "fetch_request");
        return this;
    }

    /**
     * 标记为OP 向 RP 的回复
     * 
     * @return
     */
    public Ax response() {
        put("mode", "fetch_response");
        return this;
    }

    public Ax setAxValue(String ns, String value) {
        String name = getAxName(ns);
        if (name == null) {
            name = "x" + (ns.hashCode() & 0x0FFFF);
            put("type." + name, ns);
        }
        put("value." + name, value);
        return this;
    }

    public Ax xCountry(String v) {
        return setAxValue(NS_COUNTRY, v);
    }

    public Ax xEmail(String v) {
        return setAxValue(NS_EMAIL, v);
    }

    public Ax xFirstName(String v) {
        return setAxValue(NS_FIRSTNAME, v);
    }

    public Ax xLanguage(String v) {
        return setAxValue(NS_LANGUAGE, v);
    }

    public Ax xLastName(String v) {
        return setAxValue(NS_LASTNAME, v);

    }

}
